﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Business.Base;
using Business.Base.Model;
using Business.Base.Service;
using Configuration;
using PLC.Base;
using PumpAlgorithm;

namespace Business.NPSH
{
    public class NpshExperimentCaculateService  : ICaculateService
    {
            

        public BaseChartData CaculateChartData(Experiment exp)
        {
            NpshChartData chartDataInfo = new NpshChartData();

            //获取试验对象的额定数据以及试验标准。
            NpshExperiment experiment = (NpshExperiment)exp;
            List<ExperimentRecord> list = experiment.RecordList;

            double ratedNpsh = chartDataInfo.RatedNpsh= experiment.PumpRatedNpsh;
            double ratedHead = chartDataInfo.RatedHead = experiment.PumpRatedHead;

            int xUnitCount = Config.XAxisUnit;
            int yUnitCount = Config.YAxisUnit;

            //坐标空间的余量
            double axisMaxRate = Config.AxisMaxRate;

            //画曲线的时候的取值数量
            int drawPointCount = Config.DrawPointCount;

            Double maxAxisHead = ratedHead ;
            Double maxAxisNpsh = ratedNpsh ;

           

            //设置坐标轴的最小值
            chartDataInfo.MinXNAxis = 0.0f;
            chartDataInfo.MinYHAxis = 0.0f;
            chartDataInfo.XUnitCount = xUnitCount;
            chartDataInfo.YUnitCount = yUnitCount;

            if (list.Count == 0)
            {
                chartDataInfo.MaxXNAxis = maxAxisNpsh/ axisMaxRate;
                chartDataInfo.MaxYHAxis = maxAxisHead/ axisMaxRate;
            }
            else
            {
                #region  计算初始化
                Double[] npshList = new Double[list.Count];
                Double[] headList = new Double[list.Count];

                //获取最小流量和最大流量
                double maxNpsh = 0.0f;
                double minNpsh = Double.MaxValue;

                //获取扬程的最大值和最小值
                Double maxHead = 0.0f;
                Double minHead = Double.MaxValue;

                List<double[]> pointList = new List<double[]>();
                #endregion

                #region 
                ///
                /// 1. 在记录中找出扬程，汽蚀的最大值，如果最大值小于额定值，则坐标的最大值为额定功率/axisMaxRate
                /// 2. 记录下所有的的汽蚀和扬程的记录
                /// 
                
                for (int i = 0; i < list.Count; i++)
                {
                    NpshExperimentRecord record = (NpshExperimentRecord)list[i];
                    double npsh = npshList[i] = record.Npsh;
                    double head = headList[i] = record.StpHead;
                    
                    #region 求出汽蚀，扬程的最大值和最小值
                    //流量最大值和最小值
                    double delta = npsh - maxNpsh;

                    if (delta > double.Epsilon)
                    {
                        maxNpsh = npsh;
                    }
                    delta = minNpsh -npsh;
                    if (delta > Double.Epsilon)
                    {
                        minNpsh = npsh;
                    }

                    //扬程最大值和最小值
                    
                    delta = head  - maxHead;
                    if (delta >Double.Epsilon)
                    {
                        maxHead = head;
                    }
                    delta = minHead - head;
                    if (delta > Double.Epsilon)
                    {
                        minHead = head;
                    }

                    #endregion


                    double[] data = new double[2] { npsh,head };
                    pointList.Add(data);
                }

                chartDataInfo.InputPoints = pointList;
                #endregion

                maxAxisNpsh = maxAxisNpsh - maxNpsh > Double.Epsilon ? maxAxisNpsh : maxNpsh;
                maxAxisHead = maxAxisHead - maxHead > Double.Epsilon ? maxAxisHead : maxHead;

                //求出最大值，并且做一个坐标余量的计算。
                chartDataInfo.MaxXNAxis = maxAxisNpsh/ axisMaxRate;
                chartDataInfo.MaxYHAxis = maxAxisHead/ axisMaxRate;




                #region 根据测试出的数据拟合出曲线

                double preRatedHead = 0.97 * ratedHead;
                chartDataInfo.PreRatedHead = preRatedHead;

                if (list.Count > 2)
                {
                    Double[] paramNpsh = CanonicalAlgorithm.Solve(npshList, headList);
                    #region 如果计算的值不是数字，则不画曲线
                    Boolean needDrawLine = true;
                    for (int i = 0; i < paramNpsh[i]; i++)
                    {
                        if (Double.IsInfinity(paramNpsh[i]) || Double.IsNaN(paramNpsh[i]))
                        {
                            needDrawLine = false;
                        }
                    }

                    #endregion

                    if (needDrawLine)
                    {
                        //根据公式，平均选取30个点，用于报表中画曲线的点
                        Double[] xValue = new Double[drawPointCount + 1];
                        Double[] yhValue = new Double[drawPointCount + 1];
                        double dd = (maxNpsh - minNpsh) / drawPointCount;
                        for (int i = 0; i <= drawPointCount; i++)
                        {
                            xValue[i] = minNpsh + i * dd;
                            Double npsh = xValue[i];
                            yhValue[i] = CanonicalAlgorithm.CaculateValue(npsh, paramNpsh);
                          
                            chartDataInfo.DrawList.Add(new double[2] { xValue[i], yhValue[i] });
                            //System.Console.WriteLine("{0}，{1},", xValue[i], yhValue[i]);
                        }
                        #region 根据额定扬程下降3个点计算出必须的汽蚀余量


                        double npshR;

                        List<Double[]> result = CanonicalAlgorithm.SolveEquations(0, preRatedHead, 0, ratedNpsh, paramNpsh);
                        if (result.Count == 1)
                        {
                            npshR = result[0][0];
                            chartDataInfo.NPSHR = npshR;
                        }
                        else if(result.Count >=2)
                        {

                            double diff = Double.MaxValue;
                            int index = -1;
                            for (int i = 0; i < result.Count; i++)
                            {
                                double d = Math.Abs(result[i][0] - ratedNpsh);
                                if (diff - d > Double.Epsilon)
                                {
                                    index = i;
                                    diff = d; 
                                }
                            }
                            npshR = result[index][0];
                            chartDataInfo.NPSHR = npshR;
                        }
                        


                #endregion
                    }
                }

                #endregion

                
            }

            return chartDataInfo;
        }

        public  ExperimentRecord CaculateDataFromRecord(Experiment exp,EnvData data)
        {
            NpshExperiment experiment = (NpshExperiment)exp;
            CanonicalAlgorithm canonicalAlgorithm = new CanonicalAlgorithm(
                experiment.ZInlet,
                experiment.ZOutlet,
                experiment.KInlet,
                experiment.KOutlet,
                experiment.DInlet,
                experiment.DOutlet,
                experiment.LInlet,
                experiment.LOutlet,
                experiment.MotorRatedEfficiency,
                experiment.MotorRatedSpeed
                );
            canonicalAlgorithm.setplcEnvData(data);
            canonicalAlgorithm.Calculate();

            NpshExperimentRecord record = new NpshExperimentRecord();
            
            record.ElectricCurrent = data.Current;
            record.Voltage = data.Voltage;
            record.WorkingFlow = data.Flow;
            record.Temperature = data.Temperature;
            record.PresureIn = data.PresureIn;
            record.PresureOut = data.PresureOut;
            record.WorkingPower = data.ShaftPower;
            record.WorkingSpeed = data.Speed;


            record.WorkingHead = canonicalAlgorithm.WorkingHead;
            //record.WorkingHead = canonicalAlgorithm.HeadForNpsh;
            record.Npsh = canonicalAlgorithm.Npsh;
            record.StpHead = canonicalAlgorithm.StpHead;
            return record;
        }

        public  void CaculateExperimentResult(ref Experiment experiment)
        {
            
        }

        public void ReCaculateRecord(Experiment exp)
        {
            throw new NotImplementedException();
        }
    }
}
